package com.yonyou.isv.demo.openapi.base.module.auth.isv.impl;

import com.yonyou.isv.demo.openapi.base.properties.OpenApiProperties;
import com.yonyou.isv.demo.openapi.base.datacenter.DataCenterUrlProvider;
import com.yonyou.isv.demo.openapi.base.exception.BusinessException;
import com.yonyou.isv.demo.openapi.base.module.auth.isv.ISVAuthProvider;
import com.yonyou.isv.demo.openapi.base.module.auth.pojo.OpenApiAccessTokenResponse;
import com.yonyou.isv.demo.openapi.base.module.common.OpenApiAccessToken;
import com.yonyou.isv.demo.openapi.base.network.OpenApiRequestEncryptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.TreeMap;

/**
 * 本类主要用于
 *
 * @author liuhaoi
 * @since Created At 2020/5/25 2:24 下午
 */
@Slf4j
@RequiredArgsConstructor
public class ISVAuthProviderImpl implements ISVAuthProvider {

    private static final String URL_ISV_ACCESS_TOKEN = "open-auth/suiteApp/getAccessToken";

    private final RestTemplate restTemplate;
    private final OpenApiProperties properties;
    private final OpenApiRequestEncryptor encryptor;
    @Resource
    DataCenterUrlProvider dataCenterUrlProvider;

    @Override
    public OpenApiAccessToken buildISVAuthToken() {
        String tenantId = dataCenterUrlProvider.queryTenantId();
        if (StringUtils.isBlank(tenantId)) {
            throw new BusinessException("tenant id can not be empty when request open api access token for isv");
        }
        return queryAccessTokenFromRemote(tenantId);
    }

    private OpenApiAccessToken queryAccessTokenFromRemote(String tenantId) {

        if (StringUtils.isBlank(tenantId)) {
            throw new BusinessException("tenantId is required when request isv access token");
        }

        Map<String, String> params = new TreeMap<>();
        params.put("tenantId", tenantId);

        String host = dataCenterUrlProvider.buildTokenUrl();
        URI uri = buildRequestUri(host, params, URL_ISV_ACCESS_TOKEN);

        ResponseEntity<OpenApiAccessTokenResponse> responseEntity = restTemplate
                .getForEntity(uri, OpenApiAccessTokenResponse.class);

        OpenApiAccessTokenResponse body = responseEntity.getBody();
        if (body == null) {
            throw new BusinessException("unexpected response null when request open api isv access token");
        }
        body.check();

        return body.getData().build();
    }

    private URI buildRequestUri(String host, Map<String, String> params, String urlFragment) {
        params.put("suiteKey", properties.getAppKey());
        params.put("timestamp", String.valueOf(System.currentTimeMillis()));
        String signature = encryptor.signature(params, properties.getAppSecret());
        params.put("signature", signature);

        String url = properties.concatURL(host, urlFragment, "?", properties.buildQueryString(params, false));

        URI uri;
        try {
            uri = new URI(url);
        } catch (URISyntaxException e) {
            throw new BusinessException("invalid open api uri format", e);
        }
        return uri;
    }

}
